home *** CD-ROM | disk | FTP | other *** search
Text File | 2003-10-16 | 59.5 KB | 1,594 lines |
- /*
- * SFskyedit - Star Fighter 3000 sky colours editor
- * Sky editing window
- * Copyright (C) 2001 Chris Bazley
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public Licence as published by
- * the Free Software Foundation; either version 2 of the Licence, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public Licence for more details.
- *
- * You should have received a copy of the GNU General Public Licence
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- /* ANSI library files */
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdbool.h>
- #include <limits.h>
- #include <time.h>
- #include <assert.h>
-
- /* RISC OS library files */
- #include "kernel.h"
- #include "swis.h"
- #include "wimp.h"
- #include "toolbox.h"
- #include "event.h"
- #include "wimplib.h"
- #include "window.h"
- #include "gadgets.h"
- #include "flex.h"
-
- /* My library files */
- #include "err.h"
- #include "msgtrans.h"
- #include "Macros.h"
- #include "Loader.h"
- #include "ViewsMenu.h"
- #include "SFformats.h"
- #include "Pal256.h"
- #include "NullPoll.h"
-
- /* Local headers */
- #include "Utils.h"
- #include "SFSFileInfo.h"
- #include "SFSSavebox.h"
- #include "DCS_dialogue.h"
- #include "Menus.h"
- #include "Preview.h"
- #include "Back-end.h"
- #include "Insert.h"
- #include "Interpolate.h"
- #include "EditSky.h"
- #include "Main.h"
-
- /* Key shortcuts */
- #define KEY_FILEINFO 0x01
- #define KEY_CLOSEFILE 0x02
- #define KEY_SAVEFILE 0x04
- #define KEY_SMOOTHSEL 0x05
- #define KEY_SELALL 0x06
- #define KEY_CLEARSEL 0x07
- #define KEY_EDITCOLS 0x08
- #define KEY_PREVIEW 0x0f
- #define KEY_UP 0x10
- #define KEY_DOWN 0x11
- #define KEY_PAGEUP 0x12
- #define KEY_PAGEDOWN 0x13
- #define KEY_INSERT 0x14
- #define KEY_COPY 0x15
- #define KEY_CUT 0x16
- #define KEY_PASTE 0x17
- #define KEY_DELETE 0x18
- #define KEY_INTERPOLATE 0x19
- #define KEY_HOME 0x20
- #define KEY_END 0x21
- #define KEY_TRAP 0x22
-
- /* Gadgets */
- #define GADGET_MINSKY 0x00
- #define GADGET_MINSTAR 0x01
-
- #define DRAGGING_AREA 1
- #define DRAGGING_SEL 2
-
- #define SCROLL_BORDER 64
- #define PANE_HEIGHT 140
- #define WIN_HEIGHT 3180
- #define WIN_WIDTH 548
- #define COL_HEIGHT 32
- #define GAP 16
-
- typedef char number[4];
- static int dragging_bands;
- static bool null_polling;
- static ViewData *drag_source;
- static int ghost_caret_win;
- static ViewData *ghost_caret_view;
- static int ghost_caret_position;
- static bool dragging_shift;
-
- bool def_trap_caret = true; /* state to be set for new views */
-
- /* ----------------------------------------------------------------------- */
- /* Function prototypes */
-
- static ToolboxEventHandler _EditSky_keyhandler, _EditSky_minskychanged, _EditSky_starheightchanged, _EditSky_deleted, _EditSky_colourselhandler;
-
- static WimpEventHandler _EditSky_clickhandler, _EditSky_closing, _EditSky_opening, _EditSky_redrawhandler, _EditSky_dragscroll, _EditSky_dragended, _EditSky_caretwatch, _EditSky_escwatch;
-
- static LoaderFinishedHandler _EditSky_loadfile;
- static _kernel_oserror *_EditSky_plotcursor(int x, int y, int col);
- static _kernel_oserror *_EditSky_redrawrows(int window_handle, int start_band, int end_band);
- static _kernel_oserror *_EditSky_scroll(ViewData *data, int scrollmod, int page);
- static void _EditSky_dragstopped(void);
- static _kernel_oserror *_EditSky_redrawcaret(int window_handle, int caret_position);
- static int prepare_to_insert(ViewData *view_data);
- static _kernel_oserror *scroll_win_for_caret(ViewData *view_data, int window_handle);
- static _kernel_oserror *scroll_caret_for_win(ViewData *view_data, WimpOpenWindowBlock *win_info);
-
- /* ----------------------------------------------------------------------- */
- /* Public functions */
-
- ObjectId EditSky_create(SF_SkyColours **sky, char *title, bool title_is_file)
- {
- ViewData *view_data;
-
- /* Grab memory */
- view_data = malloc(sizeof(ViewData));
- if(view_data == NULL)
- MG_RETV("NoMem", NULL_ObjectId) /* failed */
-
- if(!flex_alloc((flex_ptr)&view_data->icon_validations, 63*sizeof(colstring))) {
- MG("NoMem"); /* failed */
- goto err_exit1;
- }
- if(!flex_alloc((flex_ptr)&view_data->icon_FGcols, 63)) {
- MG("NoMem"); /* failed */
- goto err_exit2;
- }
-
- /* Create object and get object IDs of attached objects */
- if(E(toolbox_create_object(0, "EditSky", &view_data->window_id)))
- goto err_exit3;
- if(E(window_get_tool_bars(Window_InternalTopLeftToolbar, view_data->window_id, NULL, &view_data->dispvalues_pane, NULL, NULL)))
- goto err_exit4;
- if(E(window_get_menu(0, view_data->window_id, &view_data->menu)))
- goto err_exit4;
- view_data->preview_id = NULL_ObjectId;
- if(E(toolbox_set_client_handle(0, view_data->window_id, view_data)))
- goto err_exit4;
-
- /* Add entry to iconbar menu (proper title will be filled in presently) */
- if(E(ViewsMenu_add(view_data->window_id, "", "")))
- goto err_exit4;
-
- view_data->last_savepath = NULL;
- if(!EditSky_newfile(view_data, title, title_is_file))
- goto err_exit5;
-
- /* Set displayed values from skyfile header */
- if(E(numberrange_set_value(0, view_data->dispvalues_pane, GADGET_MINSKY, (*sky)->min_sky_height))
- || E(numberrange_set_value(0, view_data->dispvalues_pane, GADGET_MINSTAR, (*sky)->min_stars_height)))
- goto err_exit5;
-
- /* Register listener for files on our window */
- if(E(loader_register_listener(0, FILETYPE_SKYCOLS, view_data->window_id, NULL, load_compressed, _EditSky_loadfile, view_data)))
- goto err_exit5;
-
- /* Register Wimp event handlers */
- if(E(event_register_wimp_handler(view_data->window_id, Wimp_EMouseClick, _EditSky_clickhandler, view_data))
- || E(event_register_wimp_handler(view_data->window_id, Wimp_ERedrawWindow, _EditSky_redrawhandler, view_data))
- || E(event_register_wimp_handler(view_data->window_id, Wimp_ECloseWindow, _EditSky_closing, view_data))
- || E(event_register_wimp_handler(view_data->window_id, Wimp_EOpenWindow, _EditSky_opening, view_data))
- || E(event_register_wimp_handler(-1, Wimp_ENull, _EditSky_dragscroll, view_data))
- || E(event_register_wimp_handler(-1, Wimp_EUserDrag, _EditSky_dragended, view_data))
- || E(event_register_wimp_handler(view_data->window_id, -1, _EditSky_caretwatch, view_data)))
- goto err_exit5;
-
- /* Register Toolbox event handlers
- Note that ObjectDeleted handler is registered AFTER anything
- that could cause an error and therefore premature deletion! */
- if(!E(event_register_toolbox_handler(view_data->window_id, -1, _EditSky_keyhandler, view_data))
- && !E(event_register_toolbox_handler(pal256_sharedid, Pal256_ColourSelected, _EditSky_colourselhandler, view_data))
- && !E(event_register_toolbox_handler(view_data->dispvalues_pane, NumberRange_ValueChanged, _EditSky_minskychanged, view_data))
- && !E(event_register_toolbox_handler(view_data->dispvalues_pane, NumberRange_ValueChanged, _EditSky_starheightchanged, view_data))
- && !E(event_register_toolbox_handler(view_data->window_id, -1, _EditSky_keyhandler, view_data))
- && !E(event_register_toolbox_handler(view_data->window_id, Toolbox_ObjectDeleted, _EditSky_deleted, view_data))) {
-
- /* Its now safe to re-anchor sky data from source */
- flex_reanchor((flex_ptr)&view_data->sky, (flex_ptr)sky);
-
- /* Set colours to display */
- EditSky_rowsupdated(view_data, 0, 62);
-
- /* Init selection model */
- view_data->selection_exists = false;
- view_data->caret_position = 0;
- view_data->has_input_focus = true;
-
- view_data->trap_caret = def_trap_caret;
-
- return view_data->window_id; /* success */
- }
-
- /* Rudimentary attempt to recover from error */
- err_exit5:
- RE(ViewsMenu_remove(view_data->window_id))
- err_exit4:
- RE(toolbox_delete_object(0, view_data->window_id))
- err_exit3:
- flex_free((flex_ptr)&view_data->icon_FGcols);
- err_exit2:
- flex_free((flex_ptr)&view_data->icon_validations);
- err_exit1:
- free(view_data);
- return NULL_ObjectId; /* failed */
- }
-
- /* ----------------------------------------------------------------------- */
-
- void EditSky_paste(ViewData *view_data)
- {
- if(clipboard != NULL) {
- int insertion_pos = prepare_to_insert(view_data);
-
- insert_from_clipboard(&view_data->sky, insertion_pos);
-
- /* Select newly inserted rows */
- view_data->selection_start = insertion_pos;
- view_data->selection_end = insertion_pos + clipboard_size - 1;
- view_data->selection_exists = true;
- EditSky_rowsupdated(view_data, view_data->selection_start, 62);
- EditSky_markaschanged(view_data);
- }
- }
-
- /* ----------------------------------------------------------------------- */
-
- void EditSky_remove_sel(ViewData *view_data)
- {
- remove_bands(&view_data->sky, view_data->selection_start, view_data->selection_end);
- view_data->selection_exists = false;
- view_data->caret_position = view_data->selection_start;
- EditSky_rowsupdated(view_data, view_data->selection_start, 62);
-
- int window_handle;
- if(!E(window_get_wimp_handle(0, view_data->window_id, &window_handle)))
- RE(_EditSky_redrawcaret(window_handle, view_data->caret_position))
- //if(view_data->trap_caret)
- RE(scroll_win_for_caret(view_data, window_handle))
-
- EditSky_markaschanged(view_data);
- }
-
- /* ----------------------------------------------------------------------- */
-
- void EditSky_preview(ViewData *view_data)
- {
- /* Open a preview window, creating if necessary */
- if(view_data->preview_id == NULL) {
- view_data->preview_id = Preview_create();
- if(view_data->preview_id == NULL)
- return;
- }
- RE(window_set_title(0, view_data->preview_id, msgs_lookup_sub1("PrevTitle", tail(view_data->last_savepath, 1))))
- RE(ViewsMenu_show_object(0, view_data->preview_id, Toolbox_ShowObject_AtPointer, NULL, view_data->window_id, NULL_ComponentId)) /* (may have been iconised) */
- }
-
- /* ----------------------------------------------------------------------- */
-
- void EditSky_set_starheight(ObjectId objectref, int height)
- {
- /* Set internal and displayed data to new star height */
- ViewData *view_data;
-
- E_RET(toolbox_get_client_handle(0, objectref, (void **)&view_data))
-
- view_data->sky->min_stars_height = height;
- RE(numberrange_set_value(0, view_data->dispvalues_pane, GADGET_MINSTAR, height))
-
- /* Re-render sky preview (if any) */
- if(view_data->preview_id != NULL)
- Preview_rendersky(view_data->preview_id);
-
- /* Mark as unsaved changes */
- EditSky_markaschanged(view_data);
- }
-
- /* ----------------------------------------------------------------------- */
-
- void EditSky_set_minheight(ObjectId objectref, int height)
- {
- /* Set internal and displayed data to new min sky height */
- ViewData *view_data;
-
- E_RET(toolbox_get_client_handle(0, objectref, (void **)&view_data))
-
- view_data->sky->min_sky_height = view_data->sky->min_sky_height + height;
- RE(numberrange_set_value(0, view_data->dispvalues_pane, GADGET_MINSKY, view_data->sky->min_sky_height))
-
- /* Re-render sky preview (if any) */
- if(view_data->preview_id != NULL)
- Preview_rendersky(view_data->preview_id);
-
- /* Mark as unsaved changes */
- EditSky_markaschanged(view_data);
- }
-
- /* ----------------------------------------------------------------------- */
-
- void EditSky_clearselection(ViewData *view_data)
- {
- if(!view_data->selection_exists)
- return;
-
- int window_handle;
- E_RET(window_get_wimp_handle(0, view_data->window_id, &window_handle));
-
- /* Undraw selection */
- RE(_EditSky_redrawrows(window_handle, view_data->selection_start, view_data->selection_end))
-
- /* Set caret to nearest end of selection */
- if(absdiff(view_data->caret_position, view_data->selection_start) < absdiff((view_data->caret_position-1), view_data->selection_end))
- view_data->caret_position = view_data->selection_start;
- else
- view_data->caret_position = view_data->selection_end+1;
- view_data->selection_exists = false;
-
- /* Draw caret (must have either selection or caret) */
- RE(_EditSky_redrawcaret(window_handle, view_data->caret_position))
-
- //if(view_data->trap_caret)
- RE(scroll_win_for_caret(view_data, window_handle))
- }
-
- /* ----------------------------------------------------------------------- */
-
- void EditSky_rowsupdated(ViewData *view_data, int start_band, int end_band)
- {
- /* Re-render sky preview (if any) */
- if(view_data->preview_id != NULL)
- Preview_rendersky(view_data->preview_id);
-
- /* Update cached data used for drawing icons */
- for(int band = start_band; band <= end_band; band++) {
- unsigned int real_colour = palette[get_shade(&view_data->sky, band)];
- /* background */
- sprintf((char *)(view_data->icon_validations[band]), "C/%X", (real_colour & 0xffffff00) >> 8);
- /* foreground */
- if(brightness_of_24bit_col(real_colour) > 128)
- view_data->icon_FGcols[band] = 0x07; /* Black number */
- else
- view_data->icon_FGcols[band] = 0x00; /* White number */
- }
-
- /* Force redraw of specified colour bands */
- int window_handle;
- E_RET(window_get_wimp_handle(0, view_data->window_id, &window_handle));
- RE(_EditSky_redrawrows(window_handle, start_band, end_band))
- }
-
- /* ----------------------------------------------------------------------- */
-
- void EditSky_openparentdir(ViewData *view_data)
- {
- /* Open parent directory */
- char *last_dot = strrchr(view_data->last_savepath, (int)'.');
- if(last_dot == NULL)
- return;
- int nchars = (int)(last_dot - view_data->last_savepath);
-
- char command_buffer[14 + nchars + 1];
- strcpy(command_buffer, "Filer_OpenDir ");
- strncat(command_buffer, view_data->last_savepath, nchars);
-
- if(_kernel_oscli(command_buffer) == _kernel_ERROR)
- err_check_rep(_kernel_last_oserror());
- }
-
- /* ----------------------------------------------------------------------- */
- /* Private functions */
-
- static _kernel_oserror *_EditSky_redrawrows(int window_handle, int start_band, int end_band)
- {
- return wimp_force_redraw(window_handle, 0, -WIN_HEIGHT + start_band*(COL_HEIGHT+GAP) + GAP/2, WIN_WIDTH, -WIN_HEIGHT + (end_band+1)*(COL_HEIGHT+GAP) + GAP/2);
- }
-
- /* ----------------------------------------------------------------------- */
-
- static _kernel_oserror *_EditSky_redrawcaret(int window_handle, int caret_position)
- {
- return wimp_force_redraw(window_handle, 0, -WIN_HEIGHT + caret_position*(COL_HEIGHT+GAP), WIN_WIDTH, -WIN_HEIGHT + caret_position*(COL_HEIGHT+GAP) + GAP);
- }
-
- /* ----------------------------------------------------------------------- */
-
- static int _EditSky_keyhandler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
- {
- /* Handle key short-cuts */
- ViewData *view_data = (ViewData *)handle;
-
- switch(event_code) {
- /* ------------------------------------------- */
- /* General file operations */
-
- case KEY_FILEINFO:
- RE(open_topleftofwin(Toolbox_ShowObject_AsMenu, fileinfo_sharedid, id_block->self_id, id_block->self_id, NULL_ComponentId))
- return 1; /* claim event */
-
- case KEY_CLOSEFILE:
- if(null_polling && drag_source == view_data) {
- /* Stop drag before closing window */
- RE(wimp_drag_box((WimpDragBox *)-1));
- _EditSky_dragstopped();
- }
-
- if(view_data->changed_since_save) {
- /* Wait for response */
- dcs_openparent = false;
- RE(open_topleftofwin(Toolbox_ShowObject_AsMenu, dcs_sharedid, id_block->self_id, id_block->self_id, NULL_ComponentId))
- }
- else
- RE(toolbox_delete_object(0, id_block->self_id))
- return 1; /* claim event */
-
- case KEY_SAVEFILE:
- /* Open savebox */
- RE(open_topleftofwin(Toolbox_ShowObject_AsMenu, savebox_sharedid, id_block->self_id, id_block->self_id, NULL_ComponentId))
- return 1; /* claim event */
-
- case KEY_SELALL:
- EditSky_changeselection(view_data, 0, 62);
- //goto update_menu_if_child;
- return 1; /* claim event */
-
- case KEY_CLEARSEL:
- EditSky_clearselection(view_data);
- //goto update_menu_if_child;
- return 1; /* claim event */
-
- case KEY_PREVIEW: /* Show interactive preview */
- EditSky_preview(view_data);
- return 1; /* claim event */
-
- case KEY_UP:
- if(view_data->selection_exists) {
- if(view_data->selection_end+1 < 63)
- EditSky_set_caretpos(view_data, view_data->selection_end+2);
- else
- EditSky_set_caretpos(view_data, view_data->selection_end+1);
- } else {
- if(view_data->caret_position < 63)
- EditSky_set_caretpos(view_data, view_data->caret_position+1);
- }
- //RE(_EditSky_scroll(view_data, +(COL_HEIGHT+GAP), 0));
- return 1; /* claim event */
-
- case KEY_DOWN:
- if(view_data->selection_exists) {
- if(view_data->selection_start > 0)
- EditSky_set_caretpos(view_data, view_data->selection_start-1);
- else
- EditSky_set_caretpos(view_data, view_data->selection_start);
- } else {
- if(view_data->caret_position > 0)
- EditSky_set_caretpos(view_data, view_data->caret_position-1);
- }
- //RE(_EditSky_scroll(view_data, -(COL_HEIGHT+GAP), 0));
- return 1; /* claim event */
-
- case KEY_PAGEUP:
- RE(_EditSky_scroll(view_data, +1, 1))
- return 1; /* claim event */
-
- case KEY_PAGEDOWN:
- RE(_EditSky_scroll(view_data, -1, 1))
- return 1; /* claim event */
-
- case KEY_HOME:
- RE(_EditSky_scroll(view_data, +1, 2))
- return 1; /* claim event */
-
- case KEY_END:
- RE(_EditSky_scroll(view_data, -1, 2))
- return 1; /* claim event */
-
- /* ------------------------------------------- */
- /* Operations on selection */
-
- case KEY_SMOOTHSEL:
- /* stupidity checks - need at least three */
- if(view_data->selection_exists && ((view_data->selection_end+1) - view_data->selection_start) > 2) {
- smooth_section(&view_data->sky, view_data->selection_start, view_data->selection_end);
- EditSky_rowsupdated(view_data, view_data->selection_start, view_data->selection_end);
- EditSky_markaschanged(view_data);
- }
- else
- _kernel_oswrch(7); /* beep */
- return 1; /* claim event */
-
- case KEY_EDITCOLS:
- /* stupidity checks */
- if(view_data->selection_exists) {
- if(!E(Pal256_set_colour(pal256_sharedid, get_shade(&view_data->sky, view_data->selection_start))))
- RE(open_topleftofwin(Toolbox_ShowObject_AsMenu, pal256_sharedid, id_block->self_id, id_block->self_id, NULL_ComponentId))
- }
- else
- _kernel_oswrch(7); /* beep */
- return 1; /* claim event */
-
- case KEY_COPY:
- if(!view_data->selection_exists) {
- _kernel_oswrch(7); /* beep */
- return 1; /* claim event */
- }
- copy_to_clipboard(&view_data->sky, view_data->selection_start, view_data->selection_end);
- //goto update_menu_if_child; /* ungrey paste option */
- return 1; /* claim event */
-
- case KEY_CUT:
- if(!view_data->selection_exists) {
- _kernel_oswrch(7); /* beep */
- return 1; /* claim event */
- }
- if(copy_to_clipboard(&view_data->sky, view_data->selection_start, view_data->selection_end))
- EditSky_remove_sel(view_data);
- //goto update_menu_if_child; /* ungrey paste option (cut) and/or grey selection options (delete & cut) */
- return 1; /* claim event */
-
- case KEY_DELETE:
- if(!view_data->selection_exists) {
- _kernel_oswrch(7); /* beep */
- return 1; /* claim event */
- }
- EditSky_remove_sel(view_data);
- //goto update_menu_if_child; /* ungrey paste option (cut) and/or grey selection options (delete & cut) */
- return 1; /* claim event */
-
- case KEY_INTERPOLATE:
- /* stupidity checks - need at least two */
- if(view_data->selection_exists && ((view_data->selection_end+1) - view_data->selection_start) > 1) {
- RE(wimp_create_menu(CloseMenu,0,0))
- RE(open_topleftofwin(0, Interpolate_sharedid, id_block->self_id, id_block->self_id, NULL_ComponentId));
- }
- else
- _kernel_oswrch(7); /* beep */
- return 1; /* claim event */
-
- /* ------------------------------------------- */
- /* Operations at caret */
-
- case KEY_PASTE:
- EditSky_paste(view_data);
- //goto update_menu_if_child;
- return 1; /* claim event */
-
- case KEY_INSERT:
- /* stupidity checks - must have caret as insertion point */
- if(!view_data->selection_exists) {
- RE(wimp_create_menu(CloseMenu,0,0))
- RE(open_topleftofwin(0, Insert_sharedid, id_block->self_id, id_block->self_id, NULL_ComponentId));
- }
- else
- _kernel_oswrch(7); /* beep */
- return 1; /* claim event */
-
- case KEY_TRAP:
- view_data->trap_caret = !view_data->trap_caret;
- def_trap_caret = view_data->trap_caret;
- //{
- // ObjectId menus_ancestor;
- // if(!E(toolbox_get_ancestor(0, SkyMenu_sharedid, &menus_ancestor, NULL)) && menus_ancestor == id_block->self_id)
- // SkyMenu_update(view_data); /* tick/untick menu item */
- //}
- return 1; /* claim event */
-
- default:
- return 0; /* not interested */
- }
- /* Update of open menus is dodgy, so this doesn't really work... */
- //update_menu_if_child:
- //{
- // ObjectId menus_ancestor;
- // if(!E(toolbox_get_ancestor(0, SkyMenu_sharedid, &menus_ancestor, NULL)) && menus_ancestor == id_block->self_id) {
- // EditMenu_update(view_data);
- // ColsMenu_update(view_data);
- // }
- //}
- //return 1; /* claim event */
- }
-
- /* ======================== Wimp event handlers ========================== */
-
- static int _EditSky_escwatch(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle)
- {
- /* Check whether ESC pressed */
- _kernel_oserror *err;
- int esc;
-
- esc = _kernel_osbyte(129, (112^0xff), 0xff);
- if(esc == _kernel_ERROR) {
- err = _kernel_last_oserror();
- err_complain(err->errnum, err->errmess);
- }
-
- if((esc & 0xff) == 0xff) {
- /* STOP THAT DRAG NOW!!! */
- RE(wimp_drag_box((WimpDragBox *)-1));
- _EditSky_dragstopped();
- }
- return 0; /* event not handled */
- }
-
- /* ----------------------------------------------------------------------- */
-
- static int _EditSky_caretwatch(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle)
- {
- /* Keep track of whether this view has the input focus */
- ViewData *view_data = (ViewData *)handle;
- int window_handle;
-
- E_RETV(window_get_wimp_handle(0, id_block->self_id, &window_handle), 0);
-
- switch(event_code) {
- case Wimp_ELoseCaret:
- view_data->has_input_focus = false;
- RE(_EditSky_redrawcaret(window_handle, view_data->caret_position))
- return 1; /* claim event */
-
- case Wimp_EGainCaret:
- view_data->has_input_focus = true;
- RE(_EditSky_redrawcaret(window_handle, view_data->caret_position))
- return 1; /* claim event */
-
- default:
- return 0; /* don't handle this event */
- }
- }
-
- /* ----------------------------------------------------------------------- */
-
- static int _EditSky_dragended(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle)
- {
- ViewData *dest_data = (ViewData *)handle;
-
- _EditSky_dragstopped();
- if(dragging_bands != DRAGGING_AREA || ghost_caret_win == -1)
- return 1; /* so what? */
-
- /* Area drag dropped - check to see if drag ended on this view */
- int dest_win_handle;
- E_RETV(window_get_wimp_handle(0, dest_data->window_id, &dest_win_handle), 0)
-
- WimpGetPointerInfoBlock pointer;
- E_RETV(wimp_get_pointer_info(&pointer), 0)
- if(pointer.window_handle != dest_win_handle || !drag_source->selection_exists)
- return 0; /* event not handled */
-
- if(dest_data == drag_source && ghost_caret_position > drag_source->selection_start && ghost_caret_position < (drag_source->selection_end+1))
- return 1; /* Can't copy block into self */
-
- int length_to_copy = drag_source->selection_end - drag_source->selection_start + 1;
-
- /* Must buffer data or source block may move with open_gap */
- char *tempstore;
- if(!flex_alloc((flex_ptr)&tempstore, length_to_copy))
- RG_RETV("NoMem", 1) /* claim event */
-
- /* Copy from selection to buffer */
- for(int band = 0; band < length_to_copy; band++)
- tempstore[band] = get_shade(&drag_source->sky, drag_source->selection_start + band);
-
- /* Should we remove source data? */
- bool move_not_copy;
- if((!dragging_shift && drag_source == dest_data)
- || (dragging_shift && drag_source != dest_data))
- move_not_copy = true;
- else
- move_not_copy = false;
-
- /* ====== NOW STUFF STARTS SHIFTING AROUND! ======= */
- if(move_not_copy) {
- if(dest_data == drag_source && ghost_caret_position > drag_source->selection_end)
- ghost_caret_position -= (drag_source->selection_end+1) - drag_source->selection_start;
-
- /* Remove source data */
- EditSky_remove_sel(drag_source);
- }
-
- /* If dropped on selection in destination view then replace */
- if(dest_data != drag_source && dest_data->selection_exists && ghost_caret_position > dest_data->selection_start && ghost_caret_position < (dest_data->selection_end+1)) {
- remove_bands(&dest_data->sky, dest_data->selection_start, dest_data->selection_end);
- ghost_caret_position = dest_data->selection_start;
- }
-
- /* Copy from buffer to ghost caret position */
- open_gap(&dest_data->sky, ghost_caret_position, length_to_copy);
- for(int band = 0; band < length_to_copy && (ghost_caret_position+band) < 63; band++)
- write_shade(&dest_data->sky, ghost_caret_position+band, tempstore[band]);
- flex_free((flex_ptr)&tempstore); /* free temporary buffer */
- EditSky_rowsupdated(dest_data, ghost_caret_position, 62);
-
- if(move_not_copy || dest_data != drag_source) {
- /* Moved within view or moved/copied to diff view
- - Select destination data */
- if(dest_data->selection_exists)
- /* Wipe current selection */
- RE(_EditSky_redrawrows(dest_win_handle, dest_data->selection_start, dest_data->selection_end))
- else
- /* Wipe current caret */
- RE(_EditSky_redrawcaret(dest_win_handle, dest_data->caret_position))
-
- dest_data->selection_start = ghost_caret_position;
- dest_data->selection_end = ghost_caret_position + length_to_copy - 1;
- if(dest_data->selection_end > 62)
- dest_data->selection_end = 62;
- if(ghost_caret_position > 62) {
- dest_data->selection_exists = false;
- dest_data->caret_position = ghost_caret_position;
- RE(_EditSky_redrawcaret(dest_win_handle, ghost_caret_position))
- }
- else
- dest_data->selection_exists = true;
- /* has already been redrawn */
- }
- else {
- /* Copied within same view
- - e.g. still source selected but may have moved */
- if(drag_source->selection_exists) {
- /* If copied above selection it stays put */
- if(drag_source->selection_start > ghost_caret_position) {
- /* Have copied below - budge the selection up */
- drag_source->selection_start += length_to_copy;
- drag_source->selection_end += length_to_copy;
- /* N.B. no need to redraw new selection, as everything above the insertion point has already been redrawn */
- if(drag_source->selection_end > 62)
- drag_source->selection_end = 62;
- if(drag_source->selection_start > 62) {
- drag_source->selection_exists = false;
- drag_source->caret_position = drag_source->selection_start;
- RE(_EditSky_redrawcaret(dest_win_handle, drag_source->caret_position))
- }
- }
- }
- }
-
- EditSky_markaschanged(dest_data);
- return 1; /* claim event */
- }
-
- /* ----------------------------------------------------------------------- */
-
- static int _EditSky_dragscroll(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle)
- {
- /* Handles drag-selection, ghost caret and auto-scrolling of view */
- ViewData *view_data = (ViewData *)handle;
-
- /* Check whether pointer is over this window */
- WimpGetPointerInfoBlock pointer;
- E_RETV(wimp_get_pointer_info(&pointer), 0)
- WimpGetWindowStateBlock window;
- E_RETV(window_get_wimp_handle(0, view_data->window_id, &(window.window_handle)), 0)
- E_RETV(wimp_get_window_state(&window), 0)
- if(window.window_handle != pointer.window_handle) {
- view_data->last_scroll = 0; /* halt scroll interval timer */
- return 0; /* event not handled */
- }
-
- int bottom_scry = (window.visible_area.ymax - window.yscroll) - WIN_HEIGHT;
- int new_ghost_pos = (pointer.y - bottom_scry + COL_HEIGHT/2)/(COL_HEIGHT+GAP);
-
- switch(dragging_bands) {
- case DRAGGING_SEL:
- /* Adjust selection */
- {
- int new_start, new_end;
- if(view_data->caret_position < new_ghost_pos) {
- new_start = view_data->caret_position;
- new_end = new_ghost_pos-1;
- }
- else {
- new_start = new_ghost_pos;
- new_end = view_data->caret_position-1;
- }
- if(new_start == new_end+1)
- EditSky_set_caretpos(view_data, new_start);
- else
- EditSky_changeselection(view_data, new_start, new_end);
- }
- break;
-
- case DRAGGING_AREA:
- /* Update ghost caret (insertion point) */
- if(ghost_caret_win != window.window_handle || ghost_caret_position != new_ghost_pos) {
- /* Undraw ghost caret (may be in another window) */
- if(ghost_caret_win != -1) {
- if(!ghost_caret_view->selection_exists || ghost_caret_position > ghost_caret_view->selection_end || ghost_caret_position <= ghost_caret_view->selection_start)
- RE(_EditSky_redrawcaret(ghost_caret_win, ghost_caret_position))
- }
-
- /* Draw ghost caret */
- ghost_caret_position = new_ghost_pos;
- ghost_caret_win = window.window_handle;
- ghost_caret_view = view_data;
- if(!view_data->selection_exists || ghost_caret_position > view_data->selection_end || ghost_caret_position <= view_data->selection_start)
- RE(_EditSky_redrawcaret(window.window_handle, ghost_caret_position))
- }
- break;
- }
-
- /* Check whether auto-scrolling is needed */
- if(pointer.x < window.visible_area.xmin || pointer.x >= window.visible_area.xmax)
- return 0; /* event not handled */
-
- {
- int scroll_diff = 0, border;
-
- /* Cope with very narrow views where borders would overlap */
- if(window.visible_area.ymax - window.visible_area.ymin < SCROLL_BORDER*2)
- border = (window.visible_area.ymax - window.visible_area.ymin)/2;
- else
- border = SCROLL_BORDER;
-
- {
- int scroll_start = (window.visible_area.ymax - PANE_HEIGHT - (2<<y_eigen)) - border;
- if(pointer.y > scroll_start && pointer.y < window.visible_area.ymax)
- scroll_diff = pointer.y - scroll_start;
- else {
- scroll_start = window.visible_area.ymin + border;
- if(pointer.y >= window.visible_area.ymin && pointer.y < scroll_start)
- scroll_diff = -(scroll_start - pointer.y);
- }
- #ifndef NDEBUG
- {char string[255];sprintf(string,"report scroll_start = %d, scroll_diff = %d", scroll_start, scroll_diff);_kernel_oscli(string);}
- #endif
- }
- if(scroll_diff != 0) {
- clock_t new_time = clock();
-
- if(view_data->last_scroll != 0) {
- /* Scroll window by amount based on elapsed time */
- clock_t time_diff;
-
- if(new_time < view_data->last_scroll)
- time_diff = new_time + (UINT_MAX - view_data->last_scroll); /* timer has wrapped! */
- else
- time_diff = new_time - view_data->last_scroll;
-
- /* Put a cap on enormous time intervals */
- if(time_diff > 25)
- time_diff = 25;
-
- /* Re-open window with modified scroll offsets */
- window.yscroll += (scroll_diff * (signed int)time_diff * 8) / border;
- RE(wimp_open_window((WimpOpenWindowBlock *)&window));
- }
-
- /* Store new time */
- if(new_time == 0)
- view_data->last_scroll = 1; /* 0 is used as a special indicator */
- else
- view_data->last_scroll = new_time;
- } else
- view_data->last_scroll = 0; /* have gone outside scroll area */
- }
- return 1; /* claim event */
- }
-
- /* ----------------------------------------------------------------------- */
-
- static int _EditSky_redrawhandler(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle)
- {
- /* Custom redraw for editing window */
- ViewData *view_data = (ViewData *)handle;
- WimpRedrawWindowBlock block;
- int more;
- int bottom_scry, left_scrx;
- char num_as_text[4];
- WimpPlotIconBlock ploticonblock;
-
- block.window_handle = ((WimpRedrawWindowRequestEvent *)event)->window_handle;
-
- /* Set common values of icons */
- ploticonblock.bbox.xmin = 8;
- ploticonblock.bbox.xmax = WIN_WIDTH-8;
- ploticonblock.data.it.buffer_size = 4;
-
- E_RETV(wimp_redraw_window(&block, &more), 1)
- while (more) {
- /* Calculate work area origin in screen coordinates */
- left_scrx = block.visible_area.xmin - block.xscroll;
- bottom_scry = block.visible_area.ymax - block.yscroll - WIN_HEIGHT;
-
- /* Which rows should be drawn? */
- int min_row = (block.redraw_area.ymin - bottom_scry) / (COL_HEIGHT+GAP);
- int max_row = (block.redraw_area.ymax - bottom_scry) / (COL_HEIGHT+GAP);
-
- /* Plot selection */
- if(view_data->selection_exists && (view_data->selection_end+1 >= min_row && view_data->selection_start <= max_row)) {
- /* N.B. the +1 is because a small part of the selection rectangle is actually plotted on the row above */
- RE(wimp_set_colour(4))
- RE(_swix(OS_Plot, _INR(0,2),
- 4, /* Move, absolute */
- left_scrx,
- bottom_scry + view_data->selection_start*(COL_HEIGHT+GAP) + GAP/2
- ))
- RE(_swix(OS_Plot, _INR(0,2),
- 96+5, /* Rect, absolute */
- left_scrx + WIN_WIDTH - 1,
- bottom_scry + (view_data->selection_end+1)*(COL_HEIGHT+GAP) + GAP/2 - 1
- ))
- }
-
- /* Plot sky shades */
- for(int row = min_row;row <= max_row;row++) {
- /* We don't have data for an infinite number of bands... */
- if(row > -1 && row < 63) {
- /* Plot colour band */
- ploticonblock.bbox.ymin = -WIN_HEIGHT + (row*(COL_HEIGHT+GAP)) + GAP;
- ploticonblock.bbox.ymax = ploticonblock.bbox.ymin + COL_HEIGHT;
- ploticonblock.flags = WimpIcon_Text
- | WimpIcon_Indirected
- | WimpIcon_HCentred
- | WimpIcon_VCentred
- | WimpIcon_Filled
- | (WimpIcon_FGColour * view_data->icon_FGcols[row]);
- if(view_data->selection_exists && row >= view_data->selection_start && row <= view_data->selection_end) {
- ploticonblock.flags |= WimpIcon_Border;
- sprintf(num_as_text, "%d", row);
- }
- else
- *num_as_text = 0;
- ploticonblock.data.it.buffer = num_as_text;
- ploticonblock.data.it.validation = (char *)(view_data->icon_validations[row]);
- RE(wimp_plot_icon(&ploticonblock))
- }
-
- /* Plot caret */
- if(view_data->caret_position == row && !view_data->selection_exists) {
- int col;
- if(view_data->has_input_focus)
- col = 11; /* red */
- else
- col = 3; /* grey */
- RE(_EditSky_plotcursor(left_scrx+4, bottom_scry+(row*(COL_HEIGHT+GAP))+8, col))
- }
-
- /* Plot ghost caret */
- if(null_polling && dragging_bands == DRAGGING_AREA && block.window_handle == ghost_caret_win && ghost_caret_position == row) {
- if(!view_data->selection_exists || ghost_caret_position > view_data->selection_end || ghost_caret_position <= view_data->selection_start) {
- RE(_EditSky_plotcursor(left_scrx+4, bottom_scry+(row*(COL_HEIGHT+GAP))+8, 14)) /* orange */
- }
- }
- }
-
- /* Get next redraw rectangle */
- E_RETV(wimp_get_rectangle(&block, &more), 1)
- }
- return 1; /* claim event */
- }
-
- /* ----------------------------------------------------------------------- */
-
- static _kernel_oserror *_EditSky_scroll(ViewData *view_data, int scrollmod, int page)
- {
- /* Vertically scroll our editing window */
- WimpGetWindowInfoBlock window;
-
- THROW(window_get_wimp_handle(0, view_data->window_id, &(window.window_handle)))
- THROW(wimp_get_window_info_no_icon_data(&window))
- switch(page) {
- case 0:
- window.window_data.yscroll += scrollmod;
- break;
-
- case 1:
- window.window_data.yscroll += scrollmod * ((window.window_data.visible_area.ymax - PANE_HEIGHT-(1<<y_eigen)) - window.window_data.visible_area.ymin);
- break;
-
- case 2:
- if(scrollmod > 0)
- window.window_data.yscroll = 0;
- else
- if(scrollmod < 0)
- window.window_data.yscroll = window.window_data.extent.ymin + ((window.window_data.visible_area.ymax - PANE_HEIGHT-(1<<y_eigen)) - window.window_data.visible_area.ymin);
- break;
- }
- THROW(wimp_open_window((WimpOpenWindowBlock *)&window))
- if(view_data->trap_caret)
- return scroll_caret_for_win(view_data, (WimpOpenWindowBlock *)&window);
- else
- return NULL;
- }
-
- /* ----------------------------------------------------------------------- */
-
- static _kernel_oserror *_EditSky_plotcursor(int x, int y, int col)
- {
- /* Plot cursor */
- THROW(wimp_set_colour(col))
- THROW(_swix(OS_Plot, _INR(0,2), 4, x, y+1)) /* Move, absolute */
- THROW(_swix(OS_Plot, _INR(0,2), 96+1, 540, -2)) /* Rect, relative */
- THROW(_swix(OS_Plot, _INR(0,2), 4, x+540-1, y-8)) /* Move, absolute */
- THROW(_swix(OS_Plot, _INR(0,2), 96+1, +2, 14)) /* Rect, relative */
- THROW(_swix(OS_Plot, _INR(0,2), 4, x-1, y-8)) /* Move, absolute */
- return _swix(OS_Plot, _INR(0,2), 96+1, +2, 14); /* Rect, relative */
- }
-
- /* ----------------------------------------------------------------------- */
-
- static int _EditSky_opening(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle)
- {
- ViewData *view_data = (ViewData *)handle;
-
- if(view_data->trap_caret)
- RE(scroll_caret_for_win(view_data, &event->open_window_request))
-
- ObjectId parent = NULL_ObjectId;
- ComponentId parent_component = NULL_ComponentId;
- RE(toolbox_get_parent(0, id_block->self_id, &parent, &parent_component))
- RE(toolbox_show_object(0, id_block->self_id, Toolbox_ShowObject_FullSpec, &event->open_window_request.visible_area, parent, parent_component))
-
- return 1; /* claim event */
- }
-
- /* ----------------------------------------------------------------------- */
-
- static int _EditSky_closing(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle)
- {
- WimpGetPointerInfoBlock ptr;
- ViewData *view_data = (ViewData *)handle;
- int shift_held;
- bool parent_flag;
-
- /* Check for ADJUST-click on close icon */
- if(!E(wimp_get_pointer_info(&ptr)) && FLAG_SET(ptr.button_state, Wimp_MouseButtonAdjust)) {
-
- /* Is Shift key pressed? */
- shift_held = _kernel_osbyte(129, (0^0xff), 0xff);
- if(shift_held == _kernel_ERROR) {
- err_check_rep(_kernel_last_oserror());
- return 1; /* claim event */
- }
- if((shift_held & 0xff) == 0xff) {
- /* Shift-ADJUST: open parent directory and don't attempt to close window */
- EditSky_openparentdir(view_data);
- return 1; /* claim event */
- }
- /* ADJUST click with no shift: Open parent and attempt to close window */
- parent_flag = true;
- }
- else
- parent_flag = false; /* no ADJUST click */
-
- /* Attempt to close window */
- if(view_data->changed_since_save) {
- /* Ask them whether to save or discard changes */
- dcs_openparent = parent_flag;
- RE(open_topleftofwin(Toolbox_ShowObject_AsMenu, dcs_sharedid, id_block->self_id, id_block->self_id, NULL_ComponentId))
- }
- else {
- /* No unsaved changes */
- if(parent_flag)
- EditSky_openparentdir(view_data); /* Open parent directory */
-
- /* The delete handler will do the rest... */
- RE(toolbox_delete_object(0, id_block->self_id))
- }
- return 1; /* claim event */
- }
-
- /* ----------------------------------------------------------------------- */
-
- void EditSky_set_caretpos(ViewData *view_data, int new_pos)
- {
- assert(new_pos >= 0 && new_pos <= 63);
-
- int window_handle;
- E_RET(window_get_wimp_handle(0, view_data->window_id, &window_handle))
-
- /* Clear any selection */
- if(view_data->selection_exists) {
- view_data->selection_exists = false;
- RE(_EditSky_redrawrows(window_handle, view_data->selection_start, view_data->selection_end))
- } else {
- /* if no selection existed (e.g. caret), wipe old caret */
- if(view_data->caret_position == new_pos)
- return; /* Do nothing! */
- RE(_EditSky_redrawcaret(window_handle, view_data->caret_position))
- }
-
- if(!view_data->selection_exists || new_pos <= view_data->selection_start || new_pos > view_data->selection_end)
- /* if not within area of de-selection redraw, draw new caret */
- RE(_EditSky_redrawcaret(window_handle, new_pos))
- view_data->caret_position = new_pos;
-
- RE(scroll_win_for_caret(view_data, window_handle))
- }
-
- /* ----------------------------------------------------------------------- */
-
- static int _EditSky_clickhandler(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle)
- {
- /* In order that the pseudo-transient dbox mechanism can work
- we pass mouse click events on rather than claiming them */
- WimpMouseClickEvent *wmce = (WimpMouseClickEvent *)event;
- ViewData *view_data = (ViewData *)handle;
-
- /* bypass this for drags, to speed things up */
- if(wmce->buttons == Wimp_MouseButtonSelect*256 || wmce->buttons == Wimp_MouseButtonAdjust*256) {
- /* Give our window the input focus */
- if(view_data->has_input_focus == false)
- RE(wimp_set_caret_position(wmce->window_handle, -1, 0, 0, -1, -1))
-
- /* Close any open dialogues */
- //RE(hide_shared_if_child(id_block->self_id, Interpolate_sharedid))
- //RE(hide_shared_if_child(id_block->self_id, Insert_sharedid))
- //This is now done globally
- }
-
- if(wmce->buttons == Wimp_MouseButtonMenu)
- return 0; /* event not handled */
-
- /* what row was clicked? */
- WimpGetWindowStateBlock getwincoords;
- getwincoords.window_handle = wmce->window_handle;
- E_RETV(wimp_get_window_state(&getwincoords), 0)
- int bottom_scry = (getwincoords.visible_area.ymax - getwincoords.yscroll) - WIN_HEIGHT;
- int click_pos = (wmce->mouse_y - bottom_scry + COL_HEIGHT/2)/(COL_HEIGHT+GAP);
- int selstart_scry = bottom_scry + (view_data->selection_start*(COL_HEIGHT+GAP)) + GAP;
- int selend_scry = bottom_scry + ((view_data->selection_end+1)*(COL_HEIGHT+GAP));
-
- switch(wmce->buttons) {
- case Wimp_MouseButtonSelect*256: /* SELECT click */
- if(!view_data->selection_exists || wmce->mouse_y < selstart_scry || wmce->mouse_y > selend_scry)
- EditSky_set_caretpos(view_data, click_pos);
- break;
-
- case Wimp_MouseButtonAdjust*256: /* ADJUST click */
- if(view_data->selection_exists) {
- /* Adjust nearest end of contiguous selection */
- int new_start = view_data->selection_start;
- int new_fin = view_data->selection_end;
- if(absdiff(click_pos, new_start) < absdiff(click_pos-1, new_fin))
- new_start = click_pos;
- else
- new_fin = click_pos-1;
-
- if(new_start == (new_fin+1))
- EditSky_set_caretpos(view_data, new_start);
- else
- EditSky_changeselection(view_data, new_start, new_fin);
- }
- else {
- /* Create contiguous selection from caret to here */
- if(click_pos != view_data->caret_position) {
- if(click_pos < view_data->caret_position)
- EditSky_changeselection(view_data, click_pos, view_data->caret_position-1);
- else
- EditSky_changeselection(view_data, view_data->caret_position, click_pos-1);
- }
- }
- break;
-
- case Wimp_MouseButtonSelect*16: /* SELECT or ADJUST drag */
- case Wimp_MouseButtonAdjust*16:
- if(wmce->buttons != Wimp_MouseButtonAdjust*16
- && view_data->selection_exists
- && wmce->mouse_y > selstart_scry
- && wmce->mouse_y < selend_scry) {
- /* Drag current selection */
- WimpDragBox dragbox;
- dragbox.drag_type = Wimp_DragBox_DragFixedDash;
-
- /* initial estimate of bounding box is for entire selection */
- {
- int left_scrx = getwincoords.visible_area.xmin - getwincoords.xscroll;
- dragbox.dragging_box.xmin = left_scrx+8;
- dragbox.dragging_box.xmax = left_scrx+WIN_WIDTH-8;
- }
- dragbox.dragging_box.ymin = bottom_scry + (view_data->selection_start*(COL_HEIGHT+GAP)) + GAP;
- dragbox.dragging_box.ymax = bottom_scry + (view_data->selection_end*(COL_HEIGHT+GAP)) + GAP + COL_HEIGHT;
-
- /* clip bounding box to visible area of window */
- if(dragbox.dragging_box.ymin < getwincoords.visible_area.ymin)
- dragbox.dragging_box.ymin = getwincoords.visible_area.ymin;
- if(dragbox.dragging_box.ymax > getwincoords.visible_area.ymax - PANE_HEIGHT-(2<<y_eigen))
- dragbox.dragging_box.ymax = getwincoords.visible_area.ymax - PANE_HEIGHT-(2<y_eigen);
-
- /* allow drag anywhere on the screen */
- dragbox.parent_box.xmin = 0 - (wmce->mouse_x - dragbox.dragging_box.xmin);
- dragbox.parent_box.ymin = 0 - (wmce->mouse_y - dragbox.dragging_box.ymin);
- dragbox.parent_box.xmax = (x_windlimit<<x_eigen) + (dragbox.dragging_box.xmax - wmce->mouse_x);
- dragbox.parent_box.ymax = (y_windlimit<<y_eigen) + (dragbox.dragging_box.ymax - wmce->mouse_y);
- RE(wimp_drag_box(&dragbox))
-
- ghost_caret_win = -1;
- dragging_bands = DRAGGING_AREA;
-
- /* Check whether SHIFT held */
- {
- int keypressed = _kernel_osbyte(129, (0^0xff), 0xff);
- if(keypressed == _kernel_ERROR) {
- _kernel_oserror *err = _kernel_last_oserror();
- err_complain(err->errnum, err->errmess);
- }
- dragging_shift = (keypressed & 0xff) == 0xff;
- }
-
- /* Listen for ESCAPE pressed to abort drag
- (should get first bite at cherry as registered after scroll/ghost handlers) */
- RE(event_register_wimp_handler(-1, Wimp_ENull, _EditSky_escwatch, NULL))
- }
- else {
- /* Start new selection or drag near end of existing selection */
-
- if(wmce->buttons == Wimp_MouseButtonAdjust*16 && view_data->selection_exists) {
- /* Set 'caret' (fixed endpoint) to far end of selection */
- if(absdiff(click_pos, view_data->selection_start) < absdiff(click_pos-1, view_data->selection_end))
- view_data->caret_position = view_data->selection_end+1;
- else
- view_data->caret_position = view_data->selection_start;
- }
- dragging_bands = DRAGGING_SEL;
-
- WimpDragBox dragbox;
- dragbox.drag_type = Wimp_DragBox_DragPoint;
- dragbox.parent_box.ymax = getwincoords.visible_area.ymax - PANE_HEIGHT - (2<<y_eigen);
- dragbox.parent_box.xmax = getwincoords.visible_area.xmax - (1<<x_eigen);
- dragbox.parent_box.ymin = getwincoords.visible_area.ymin;
- dragbox.parent_box.xmin = getwincoords.visible_area.xmin;
- RE(wimp_drag_box(&dragbox))
- }
-
- /* Watch out for auto-scrolling */
- nullpoll_register();
- view_data->last_scroll = 0; /* reset scroll interval timer */
- null_polling = true;
- drag_source = view_data;
- break;
-
- case Wimp_MouseButtonSelect: /* SELECT double-click */
- if(view_data->selection_exists && wmce->mouse_y > selstart_scry && wmce->mouse_y < selend_scry) {
- /* Change the colour of the selected bands */
- if(!E(Pal256_set_colour(pal256_sharedid, get_shade(&view_data->sky, (wmce->mouse_y - bottom_scry)/(COL_HEIGHT+GAP)))))
- RE(toolbox_show_object(Toolbox_ShowObject_AsMenu, pal256_sharedid, Toolbox_ShowObject_AtPointer, NULL, id_block->self_id, NULL_ComponentId))
- }
- break;
- }
- return 0; /* pass event on */
- }
-
- /* ======================== Toolbox event handlers ======================= */
-
- static int _EditSky_colourselhandler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
- {
- /* Colour selected - fill selected skyfile bands */
- ViewData *view_data = (ViewData *)handle;
-
- if(id_block->parent_id != view_data->window_id)
- return 0; /* none of our business */
-
- plain_overwrite(&view_data->sky, view_data->selection_start, view_data->selection_end, ((Pal256ColourSelectedEvent *)event)->colour_number);
- EditSky_rowsupdated(view_data, view_data->selection_start, view_data->selection_end);
- EditSky_markaschanged(view_data);
- return 1; /* claim event */
- }
-
- /* ----------------------------------------------------------------------- */
-
- static int _EditSky_minskychanged(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
- {
- NumberRangeValueChangedEvent *nrvc = (NumberRangeValueChangedEvent *)event;
- ViewData *view_data = (ViewData *)handle;
-
- if(id_block->self_component != GADGET_MINSKY || nrvc->new_value > 10000 || nrvc->new_value < 0)
- return 0; /* event not handled */
- view_data->sky->min_sky_height = nrvc->new_value;
-
- /* Re-render sky preview (if any) */
- if(view_data->preview_id != NULL)
- Preview_rendersky(view_data->preview_id);
-
- /* Mark as unsaved changes */
- EditSky_markaschanged(view_data);
- return 1; /* claim event */
- }
-
- /* ----------------------------------------------------------------------- */
-
- static int _EditSky_starheightchanged(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
- {
- NumberRangeValueChangedEvent *nrvc = (NumberRangeValueChangedEvent *)event;
- ViewData *view_data = (ViewData *)handle;
-
- if(id_block->self_component != GADGET_MINSTAR || nrvc->new_value > 10000)
- return 0; /* event not handled */
- view_data->sky->min_stars_height = nrvc->new_value;
-
- /* Re-render sky preview (if any) */
- if(view_data->preview_id != NULL)
- Preview_rendersky(view_data->preview_id);
-
- /* Mark as unsaved changes */
- EditSky_markaschanged(view_data);
- return 1; /* claim event */
- }
-
- /* ----------------------------------------------------------------------- */
-
- static int _EditSky_deleted(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
- {
- ViewData *view_data = (ViewData *)handle;
-
- /* Delete any associated preview window and close child dialogues */
- if(view_data->preview_id != NULL)
- RE(toolbox_delete_object(0, view_data->preview_id))
- RE(hide_shared_if_child(id_block->self_id, Interpolate_sharedid))
- RE(hide_shared_if_child(id_block->self_id, Insert_sharedid))
-
- /* Remove handlers */
- RE(event_deregister_toolbox_handler(id_block->self_id, Toolbox_ObjectDeleted, _EditSky_deleted, view_data))
-
- RE(event_deregister_toolbox_handler(view_data->dispvalues_pane, NumberRange_ValueChanged, _EditSky_minskychanged, view_data))
- RE(event_deregister_toolbox_handler(view_data->dispvalues_pane, NumberRange_ValueChanged, _EditSky_starheightchanged, view_data))
- RE(event_deregister_toolbox_handler(id_block->self_id, -1, _EditSky_keyhandler, view_data))
- RE(event_deregister_toolbox_handler(pal256_sharedid, Pal256_ColourSelected, _EditSky_colourselhandler, view_data))
-
- RE(event_deregister_wimp_handler(id_block->self_id, Wimp_EMouseClick, _EditSky_clickhandler, view_data))
- RE(event_deregister_wimp_handler(id_block->self_id, Wimp_ECloseWindow, _EditSky_closing, view_data))
- RE(event_deregister_wimp_handler(id_block->self_id, Wimp_EOpenWindow, _EditSky_opening, view_data))
- RE(event_deregister_wimp_handler(id_block->self_id, Wimp_ERedrawWindow, _EditSky_redrawhandler, view_data))
- RE(event_deregister_wimp_handler(-1, Wimp_ENull, _EditSky_dragscroll, view_data))
- RE(event_deregister_wimp_handler(-1, Wimp_EUserDrag, _EditSky_dragended, view_data))
- RE(event_deregister_wimp_handler(id_block->self_id, -1, _EditSky_caretwatch, view_data))
-
- RE(loader_deregister_listener(FILETYPE_SKYCOLS, id_block->self_id, NULL))
-
- RE(ViewsMenu_remove(id_block->self_id))
-
- flex_free((flex_ptr)&view_data->sky);
- flex_free((flex_ptr)&view_data->icon_FGcols);
- flex_free((flex_ptr)&view_data->icon_validations);
- free(view_data->last_savepath);
- free(view_data);
- return 1; /* claim event */
- }
-
- /* ======================= Loader finished handler ======================= */
-
- static void _EditSky_loadfile(char *title, bool data_saved, flex_ptr buffer, int filetype, void *handle)
- {
- ViewData *view_data = (ViewData *)handle;
-
- /* Check file format */
- if(!verify_sky_file((SF_SkyColours **)buffer)) {
- flex_free(buffer);
- return;
- }
-
- int insert = prepare_to_insert(view_data);
-
- /* Insert data at cursor */
- open_gap(&view_data->sky, insert, 62);
- for(int band = 0; band < 63 && (insert+band) < 63; band++)
- write_shade(&view_data->sky, insert+band, get_shade((SF_SkyColours **)buffer, band));
- flex_free(buffer);
-
- /* Update displayed colours */
- view_data->selection_exists = true;
- view_data->selection_start = insert;
- view_data->selection_end = 62;
- EditSky_rowsupdated(view_data, insert, 62);
-
- /* Set displayed values from header */
- RE(numberrange_set_value(0, view_data->dispvalues_pane, GADGET_MINSKY, view_data->sky->min_sky_height))
- RE(numberrange_set_value(0, view_data->dispvalues_pane, GADGET_MINSTAR, view_data->sky->min_stars_height))
-
- /* Mark as unsaved changes, and redraw preview (if any) */
- EditSky_markaschanged(view_data);
- }
-
- /* ========================== Utility functions ========================== */
-
- bool EditSky_newfile(ViewData *view_data, char *title, bool title_is_file)
- {
- _kernel_osfile_block osfb;
- char *new_ptr, *views_filepath;
-
- new_ptr = realloc(view_data->last_savepath, strlen(title) + 1);
- if(new_ptr == NULL)
- RG_RETV("NoMem", false) /* failed */
- view_data->last_savepath = new_ptr;
- strcpy(view_data->last_savepath, title); /* not necessarily /strictly/ true but what the hell */
-
- if(title_is_file) {
- /* Get datestamp of file */
- if(_kernel_osfile(17, title, &osfb) == _kernel_ERROR)
- E_RETV(_kernel_last_oserror(), false)
- if((osfb.load & 0xfff00000) == 0xfff00000) {
- /* File has datestamp and filetype */
- view_data->file_date[0] = osfb.exec;
- view_data->file_date[1] = osfb.load;
- }
- else {
- /* File has load & exec addresses */
- view_data->file_date[0] = 0;
- view_data->file_date[1] = 0;
- }
- }
- else {
- /* Get current time & date */
- view_data->file_date[0] = 3; /* Read soft-copy of CMOS clock as 5-byte integer */
- if(_kernel_osword(14, view_data->file_date) == _kernel_ERROR)
- E_RETV(_kernel_last_oserror(), false)
- }
-
- /* Set title of editing window */
- E_RETV(window_set_title(0, view_data->window_id, title), false)
- if(title_is_file)
- views_filepath = title;
- else
- views_filepath = "";
- E_RETV(ViewsMenu_setname(view_data->window_id, title, views_filepath), false)
-
- /* Set title of preview window */
- if(view_data->preview_id != NULL) {
- E_RETV(window_set_title(0, view_data->preview_id, msgs_lookup_sub1("PrevTitle", tail(title, 1))), false)
- }
-
- view_data->changed_since_save = false; /* mark as unchanged */
- return true; /* success */
- }
-
- /* ----------------------------------------------------------------------- */
-
- void EditSky_markaschanged(ViewData *view_data)
- {
- char wintitle[256];
-
- if(view_data->changed_since_save)
- return;
-
- /* Mark data as changed */
- sprintf(wintitle, "%.253s *", view_data->last_savepath);
- RE(window_set_title(0, view_data->window_id, wintitle))
- RE(ViewsMenu_setname(view_data->window_id, wintitle, NULL))
- view_data->changed_since_save = true;
- }
-
- /* ----------------------------------------------------------------------- */
-
- void EditSky_changeselection(ViewData *view_data, int newsel_start, int newsel_end)
- {
- /* Find areas to redraw when selection changed */
- int oldsel_start = view_data->selection_start;
- int oldsel_end = view_data->selection_end;
-
- int window_handle;
- E_RET(window_get_wimp_handle(0, view_data->window_id, &window_handle))
-
- if(!view_data->selection_exists) {
- /* Undraw caret */
- RE(_EditSky_redrawcaret(window_handle, view_data->caret_position))
-
- /* Draw new selection */
- RE(_EditSky_redrawrows(window_handle, newsel_start, newsel_end))
- }
- else {
- if(newsel_end < oldsel_start || oldsel_end < newsel_start) {
- /* Undraw old selection */
- RE(_EditSky_redrawrows(window_handle, oldsel_start, oldsel_end))
-
- /* Draw new selection */
- RE(_EditSky_redrawrows(window_handle, newsel_start, newsel_end))
- }
- else {
- /* Calculate shift in end positions */
- if(oldsel_start < newsel_start)
- RE(_EditSky_redrawrows(window_handle, oldsel_start, newsel_start-1))
-
- if(oldsel_start > newsel_start)
- RE(_EditSky_redrawrows(window_handle, newsel_start, oldsel_start-1))
-
- if(oldsel_end < newsel_end)
- RE(_EditSky_redrawrows(window_handle, oldsel_end+1, newsel_end))
-
- if(oldsel_end > newsel_end)
- RE(_EditSky_redrawrows(window_handle, newsel_end+1, oldsel_end))
- }
- }
- view_data->selection_exists = true;
- view_data->selection_start = newsel_start;
- view_data->selection_end = newsel_end;
- }
-
- /* ----------------------------------------------------------------------- */
-
- static void _EditSky_dragstopped(void)
- {
- if(null_polling) {
- nullpoll_deregister(); /* Stop auto-scrolling */
- null_polling = false;
-
- if(dragging_bands == DRAGGING_AREA) {
- /* Remove ghost caret */
- if(ghost_caret_win != -1)
- RE(_EditSky_redrawcaret(ghost_caret_win, ghost_caret_position))
-
- RE(event_deregister_wimp_handler(-1, Wimp_ENull, _EditSky_escwatch, NULL))
- }
- }
- }
-
- /* ----------------------------------------------------------------------- */
-
- static int prepare_to_insert(ViewData *view_data)
- {
- /* If no caret then replace selection */
- if(view_data->selection_exists) {
- remove_bands(&view_data->sky, view_data->selection_start, view_data->selection_end);
- return view_data->selection_start;
- } else {
- /* Otherwise undraw caret */
- int window_handle;
- if(!E(window_get_wimp_handle(0, view_data->window_id, &window_handle)))
- RE(_EditSky_redrawcaret(window_handle, view_data->caret_position))
- return view_data->caret_position;
- }
- }
-
- /* ----------------------------------------------------------------------- */
-
- static _kernel_oserror *scroll_win_for_caret(ViewData *view_data, int window_handle)
- {
- /* Scroll window if necessary to make caret visible */
- WimpGetWindowInfoBlock window;
- window.window_handle = window_handle;
- THROW(wimp_get_window_info_no_icon_data(&window))
-
- int WA_bot_of_caret = -WIN_HEIGHT + view_data->caret_position*(COL_HEIGHT+GAP);
- int visible_height = window.window_data.visible_area.ymax - window.window_data.visible_area.ymin;
- int old_scroll = window.window_data.yscroll;
- if(window.window_data.yscroll < PANE_HEIGHT+(1<<y_eigen) + WA_bot_of_caret + GAP) {
- window.window_data.yscroll = PANE_HEIGHT+(1<<y_eigen) + WA_bot_of_caret + GAP;
- /* Scroll in steps of 3 bands, if there is room */
- if(visible_height - PANE_HEIGHT-(1<<y_eigen) >= GAP + 3*(COL_HEIGHT+GAP))
- window.window_data.yscroll += 3*(COL_HEIGHT+GAP);
- } else {
- if(window.window_data.yscroll > WA_bot_of_caret + visible_height) {
- window.window_data.yscroll = WA_bot_of_caret + visible_height;
- /* Scroll in steps of 3 bands, if there is room */
- if(visible_height - PANE_HEIGHT-(1<<y_eigen) >= GAP + 3*(COL_HEIGHT+GAP))
- window.window_data.yscroll -= 3*(COL_HEIGHT+GAP);
- }
- }
- if(old_scroll != window.window_data.yscroll)
- THROW(wimp_open_window((WimpOpenWindowBlock *)&window))
-
- return NULL; /* success */
- }
-
- /* ----------------------------------------------------------------------- */
-
- static _kernel_oserror *scroll_caret_for_win(ViewData *view_data, WimpOpenWindowBlock *win_info)
- {
- int bottom_scry = (win_info->visible_area.ymax - win_info->yscroll) - WIN_HEIGHT;
- int WA_bot_of_caret = -WIN_HEIGHT + view_data->caret_position*(COL_HEIGHT+GAP);
- int new_caret_pos = view_data->caret_position;
-
- if(win_info->yscroll < PANE_HEIGHT+(1<<y_eigen) + WA_bot_of_caret + GAP)
- new_caret_pos = (win_info->visible_area.ymax -PANE_HEIGHT-(1<<y_eigen) - bottom_scry - GAP)/(COL_HEIGHT+GAP);
- else {
- if(win_info->yscroll > WA_bot_of_caret + (win_info->visible_area.ymax - win_info->visible_area.ymin))
- new_caret_pos = (win_info->visible_area.ymin - bottom_scry + COL_HEIGHT+GAP)/(COL_HEIGHT+GAP);
- }
- if(new_caret_pos != view_data->caret_position) {
- THROW(_EditSky_redrawcaret(win_info->window_handle, new_caret_pos))
- THROW(_EditSky_redrawcaret(win_info->window_handle, view_data->caret_position))
- view_data->caret_position = new_caret_pos;
- }
-
- return NULL; /* success */
- }
-